using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Acms.AcmsControls
{
    public class RenderFile : System.Web.UI.Page
    {
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!IsPostBack)
            {
                int id = 0;
                int width = 0;
                int height = 0;

                if (Request.QueryString["Id"] != null)
                {
                    try
                    {
                        id = int.Parse(Request.QueryString["Id"]);
                    }
                    catch
                    {
                    }
                }

                if (Request.QueryString["Width"] != null)
                {
                    try
                    {
                        width = int.Parse(Request.QueryString["Width"]);
                    }
                    catch
                    {
                    }
                }


                if (Request.QueryString["Height"] != null)
                {
                    try
                    {
                        height = int.Parse(Request.QueryString["Height"]);
                    }
                    catch
                    {
                    }
                }

                if (id > 0)
                {
                    Acms.Bll.File file = Acms.Bll.File.GetById(id);
                    if (file != null)
                    {
                        switch (file.FileType)
                        {
                            case Acms.Bll.File.FileTypes.Image:
                                RenderImage(file, width, height);
                                break;
                        }
                    }
                }
                else
                {
                    RenderError();
                }
            }

        }

        private void RenderError()
        {
            Response.StatusCode = 404;
            Response.End();
        }

        private void RenderImage(Acms.Bll.File file, int width, int height)
        {
            Bitmap bitmap = ResizeBitMap(file, width, height);
            if (bitmap != null)
            {
                switch(file.ContentType)
                {
                    case "image/jpeg":
                    case "image/pjpeg":
                        RenderJpeg(bitmap);
                        break;
                    case "image/gif":
                        RenderGif(bitmap);
                        break;
                    case "image/png":
                        RenderPng(bitmap);
                        break;
                    default:
                        RenderError();
                        break;
                }
            }
            else
            {
                RenderError();
            }
        }

        private System.Drawing.Imaging.ImageCodecInfo GetJpecEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1];
        }

        private void RenderJpeg(Bitmap bitmap)
        {
            System.Drawing.Imaging.ImageCodecInfo encoder = GetJpecEncoder();
            Response.ContentType = encoder.MimeType;
            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(1);
            parameters.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80L);
            bitmap.Save(Response.OutputStream, encoder, parameters);
            Response.End();
            bitmap.Dispose();
        }


        private System.Drawing.Imaging.ImageCodecInfo GetGifEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[2];
        }
        
        private void RenderGif(Bitmap bitmap)
        {

            System.Drawing.Imaging.ImageCodecInfo encoder = GetGifEncoder();

            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(0);

            Acms.ImageManipulation.OctreeQuantizer quantizer = new Acms.ImageManipulation.OctreeQuantizer ( 128 , 8 ) ;
            Bitmap quantized = quantizer.Quantize ( bitmap );
            bitmap.Dispose();

            Response.ContentType = encoder.MimeType;
            
            quantized.Save ( Response.OutputStream, encoder, parameters) ;

            Response.End();
            quantized.Dispose();
        }

        private System.Drawing.Imaging.ImageCodecInfo GetPngEncoder()
        {
            return System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[4];
        }

        private void RenderPng(Bitmap bitmap)
        {

            System.Drawing.Imaging.ImageCodecInfo encoder = GetPngEncoder();

            System.Drawing.Imaging.EncoderParameters parameters = new System.Drawing.Imaging.EncoderParameters(0);

            System.IO.MemoryStream mem = new System.IO.MemoryStream();
            bitmap.Save(mem, encoder, parameters);

            Response.ContentType = encoder.MimeType;
            mem.WriteTo(Response.OutputStream);
            Response.End();
            
            bitmap.Dispose();
        }

        private Bitmap CreateBitmap(Acms.Bll.File file)
        {
            System.IO.MemoryStream mem = file.GetFileStream();

            if (mem != null)
            {
                Bitmap bitmap = new Bitmap(mem);
                return bitmap;
            }
            else
            {
                return null;
            }
        }

        private decimal GetResizeFactor(int targetWidth, int targetHeight, int imageWidth, int imageHeight)
        {
            decimal factor = 1;
            if (targetWidth != 0 && targetHeight != 0 && (imageWidth > targetWidth || imageHeight > targetHeight))
            {
                decimal widthFactor = (decimal)targetWidth / (decimal)imageWidth;
                decimal heightFactor = (decimal)targetHeight / (decimal)imageHeight;

                if (widthFactor > heightFactor)
                {
                    factor = heightFactor;
                }
                else
                {
                    factor = widthFactor;
                }
            }
            else if (targetWidth != 0 && imageWidth > targetWidth)
            {
                factor = (decimal)targetWidth / (decimal)imageWidth;
            }
            else if (targetHeight != 0 && imageHeight > targetHeight)
            {
                factor = (decimal)targetHeight / (decimal)imageHeight;
            }
            return factor;
        }

        private Bitmap ResizeBitMap(Bitmap bitmap, int width, int height)
        {
            if (bitmap != null)
            {
                //get the fractor to shrink by
                decimal factor = GetResizeFactor(width, height, bitmap.Width, bitmap.Height);
                int actualWidth = (int)Math.Ceiling(Math.Round(bitmap.Width * factor, 1));
                int actualHeight = (int)Math.Ceiling(Math.Round(bitmap.Height * factor, 1));

                Bitmap resized = new Bitmap(actualWidth, actualHeight);
                Graphics g = Graphics.FromImage(resized);

                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.SmoothingMode  = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                g.FillRectangle(Brushes.White, 0, 0, actualWidth, actualHeight);
                
                g.DrawImage(bitmap, 0, 0, actualWidth, actualHeight);
                g.Dispose();
                bitmap.Dispose();
                return resized;
            }
            else
            {
                return null;
            }
        }

        private Bitmap ResizeBitMap(Acms.Bll.File file, int width, int height)
        {
            Bitmap bitmap = CreateBitmap(file);
            if (bitmap != null)
            {
                return ResizeBitMap(bitmap, width, height);
            }
            else
            {
                return null;
            }
        }
    }
}
